
namespace Nutils
{
    public class Console
    {
        public enum Levels
        {
            NONE = 0,
            SPAM = 1 << 1,
            NOTIFY = 1 << 2,
            ERROR = 1 << 3,
            ALL = 0xfffffff
        }


        public delegate void SetString(string s);
        private class _StringOut : _IConsole
        {
            SetString _SetStringFunc;
            bool _TimeStamped;

            public _StringOut(SetString targetStr, Levels eLevels, bool TimeStamped)
                : base(eLevels)
            {
                _SetStringFunc = new SetString(targetStr);
                _TimeStamped = TimeStamped;
            }

            override public void WriteLine(string text)
            {
                if (_TimeStamped)
                {
                    _SetStringFunc(TimeStamp + text);
                }
                else
                {
                    _SetStringFunc(text);
                }
            }
        }


        public static void AddFileTrace(string fileName, bool bAppend, Levels eLevels)
        {
            if (_traces == null)
            {
                _traces = new _IConsoleList();
            }

            _traces.Add(new _FileOut(fileName, bAppend, eLevels));
        }

        public static void AddStringTrace(SetString StringSetFunc, Levels eLevels)
        {
            if (_traces == null)
            {
                _traces = new _IConsoleList();
            }

            _traces.Add(new _StringOut(StringSetFunc, eLevels, false));
        }

        public static void ClearTraces()
        {
            _traces.Clear();
        }

        public static void AddTimeStampedStringTrace(SetString StringSetFunc, Levels eLevels)
        {
            if (_traces == null)
            {
                _traces = new _IConsoleList();
            }

            _traces.Add(new _StringOut(StringSetFunc, eLevels, true));
        }

        public static void Error(string text)
        {
            _WriteLine("Error:  " + text, Levels.ERROR);
        }

        public static void Exception(System.Exception ex)
        {
            _WriteLine("Exception:  " + ex.Message, Levels.ERROR);
            _WriteLine(ex.StackTrace, Levels.ERROR);
        }

        public static void Notify(string text)
        {
            _WriteLine("Notify: " + text, Levels.NOTIFY);
        }

        public static void Spam(string text)
        {
            _WriteLine(text, Levels.SPAM);
        }




        private static void _WriteLine(string text, Levels nLevel)
        {
            if (_traces == null || _traces.Count < 1)
            {
                return;
            }

            foreach (_IConsole trace in _traces)
            {
                if ((trace.eLevels & nLevel) == nLevel)
                {
                    trace.WriteLine(text);
                }
            }
        }
        private class _IConsoleList : System.Collections.Generic.List<_IConsole> { }
        private static _IConsoleList _traces;
        private class _IConsole
        {
            public Levels eLevels;
            public _IConsole(Levels eLevels)
            {
                this.eLevels = eLevels;
            }

            virtual public void WriteLine(string text) { }

            protected string TimeStamp
            {
                get
                {
                    return System.DateTime.Now.ToString() + ": ";
                }
            }
        }

        private class _FileOut : _IConsole
        {
            private System.IO.StreamWriter streamWriter;

            public _FileOut(string fileName, bool bAppend, Levels eLevels)
                : base(eLevels)
            {
                streamWriter = new System.IO.StreamWriter(fileName, bAppend);
                streamWriter.WriteLine();
                streamWriter.WriteLine();
                streamWriter.WriteLine(TimeStamp + "\tBegin");
                streamWriter.Flush();
            }

            ~_FileOut()
            {
                streamWriter.WriteLine(TimeStamp + "\tEnd");
                //streamWriter.Flush();
            }

            override public void WriteLine(string text)
            {
                streamWriter.WriteLine(TimeStamp + text);
                streamWriter.Flush();
            }
        }
    }
}